package com.tc.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.tc.backend.user.dto.resp.FindUserByPhoneRspDTO;
import com.tc.biz.context.holder.LoginUserContextHolder;
import com.tc.common.enums.DeleteEnum;
import com.tc.common.enums.StatusEnum;
import com.tc.config.PasswordEncoderConfig;
import com.tc.constant.RedisConstants;
import com.tc.constant.RoleConstatns;
import com.tc.domain.dataobject.RoleDO;
import com.tc.domain.dataobject.UserDO;
import com.tc.domain.dataobject.UserRoleRelDO;
import com.tc.domain.mapper.RoleDOMapper;
import com.tc.domain.mapper.UserDOMapper;
import com.tc.common.enums.LoginTypeEnum;
import com.tc.common.enums.ResponseCodeEnum;
import com.tc.common.exception.BizException;
import com.tc.domain.mapper.UserRoleRelDOMapper;
import com.tc.model.dto.UpdateUserInfoDTO;
import com.tc.model.vo.LoginReqVO;
import com.tc.common.response.Response;
import com.tc.model.vo.UpdatePasswordReqVO;
import com.tc.operationlog.JsonUtils;
import com.tc.rpc.UserRpcService;
import com.tc.service.UserService;
import com.tc.sms.AliyunSmsHelper;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.google.common.base.Preconditions;
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Resource
    private UserDOMapper userMapper;
    @Resource
    private RoleDOMapper roleDOMapper;
    @Resource
    private UserRoleRelDOMapper userRoleRelDOMapper;

    // 为用户注册提供编程式注解 保证出现异常回滚
    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private RedisTemplate redisTemplate;
    @Resource(name = "taskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private AliyunSmsHelper aliyunSmsHelper;

    @Resource
    private UserRpcService userRpcService;
    @Override
    public Response<String> loginAndRegister(LoginReqVO loginReqVO) {
        // 拿到用户传来的数据
        String phone = loginReqVO.getPhone();
        Integer type = loginReqVO.getType();
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);

        // 获取UserId 用户后续的反参
        Long userID = null;

        UserDO user = new UserDO();
        switch (loginTypeEnum) {
            case VERFICATION_CODE:
                // 验证码判空
                String code = loginReqVO.getCode();
                Preconditions.checkArgument(StringUtils.isNotBlank(code), "验证码不能为空");
                // 验证验证码是否匹配 验证码存在redis里面
                // 查redis 前构建key 参数
                String key = RedisConstants.buildVerification(phone);
                String code_from_redis = (String) redisTemplate.opsForValue().get(key);
                log.info("code redis code :{} {}", code,  code_from_redis);
                if (!code.equals(code_from_redis)){
                    throw new BizException(ResponseCodeEnum.VERFICATION_CODE_ERROR);
                }
                // 验证码相等 查数据库 看用户是否注册过
                UserDO userDO = userMapper.selectByPhone(phone);
                if (Objects.isNull(userDO)){
                    // 未注册 进入注册逻辑
                    Long registerUserId = userRpcService.registerUser(phone);
                    if (Objects.isNull(registerUserId)) {
                        throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                    }
                    userID = registerUserId;
                }else {
                    userID = userDO.getId();
                }
                break;
            case PASSWORD_CODE: // 密码登录
                String password = loginReqVO.getPassword();

                // RPC: 调用用户服务，通过手机号查询用户
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRpcService.findUserByPhone(phone);

                // 判断该手机号是否注册
                if (Objects.isNull(findUserByPhoneRspDTO)) {
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }

                // 拿到密文密码
                String encodePassword = findUserByPhoneRspDTO.getPassword();

                // 匹配密码是否一致
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);

                // 如果不正确，则抛出业务异常，提示用户名或者密码不正确
                if (!isPasswordCorrect) {
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }

                userID = findUserByPhoneRspDTO.getId();
                break;
            default:
                throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }

        // 能走到这说明不管是密码还是验证码都是验证通过 直接通过SaToken 获取 JWT
        StpUtil.login(userID);

        // 获取JWT
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return Response.success(tokenInfo.tokenValue);
    }

    @Override
    public Response<UserDO> findCurrentUserInfo() {
        // 获取当前登录的用户ID
        Long userId = LoginUserContextHolder.getUserId();

        // 查询用户信息
        if (Objects.isNull(userId)){
            throw new BizException(ResponseCodeEnum.USER_NOT_LOGIN);
        }

        // 查询数据库
        UserDO user = userMapper.selectByPrimaryKey(userId);

        return Response.success(user);
    }

    @Override
    public Long register(LoginReqVO loginReqVO) {

        return transactionTemplate.execute(status -> {
            try {
                // 获取全局自增的虎扑用户ID
                Long hupuID = redisTemplate.opsForValue().increment(RedisConstants.GLOBAL_HUPU_ID_GENERATOR_KEY);
                String phone = loginReqVO.getPhone();
                UserDO userDO = UserDO.builder()
                        .phone(phone)
                        .hupuId(String.valueOf(hupuID))
                        .nickname("虎扑" + hupuID)
                        .status(StatusEnum.ENABLE.getValue())
                        .birthday(LocalDateTime.now())
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .isDeleted(DeleteEnum.NO.getValue())
                        .build();
                // 入库
                userMapper.insert(userDO);

                // redis 加入用户角色信息
                // 获取添加的角色信息
                Long userDOId = userDO.getId();

                // 给用户分配一个默认的普通角色
                UserRoleRelDO userRoleRelDO = UserRoleRelDO.builder()
                        .userId(userDOId)
                        .roleId(RoleConstatns.COMMON_USER_ROLE_ID)
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .isDeleted(DeleteEnum.NO.getValue())
                        .build();
                userRoleRelDOMapper.insert(userRoleRelDO);

                // 添加到redis
                RoleDO roleDO = roleDOMapper.selectByPrimaryKey(RoleConstatns.COMMON_USER_ROLE_ID);

                // 将该用户的角色 ID 存入 Redis 中，指定初始容量为 1，这样可以减少在扩容时的性能开销
                List<String> roles = new ArrayList<>(1);
                roles.add(roleDO.getRoleKey());

                String userRolesKey = RedisConstants.buildUserRoleKey(userDOId);
                redisTemplate.opsForValue().set(userRolesKey, JsonUtils.toJsonString(roles));

                return  userDOId;

            }catch (Exception e){
                status.setRollbackOnly(); //标记事务为回滚
                log.error("==>　系统注册用户异常", e);
                return null;
            }
        });
    }

    @Override
    public Response<?> updateUserInfoByUserId(UpdateUserInfoDTO updateUserInfoDTO) {
        // 获取当前登录的用户ID
        Long userId = LoginUserContextHolder.getUserId();

        // 查询用户信息
        if (Objects.isNull(userId)){
            throw new BizException(ResponseCodeEnum.USER_NOT_LOGIN);
        }

        // 查询数据库
        UserDO user = userMapper.selectByPrimaryKey(userId);

        UserDO user1 = UserDO.builder().id(user.getId())
                .phone(user.getPhone())
                .password(SaSecureUtil.md5(updateUserInfoDTO.getPassword()))
                .nickname(updateUserInfoDTO.getNickname())
                .avatar(updateUserInfoDTO.getAvatarUrl())
                .createTime(user.getCreateTime())
                .updateTime(LocalDateTime.now())
                .build();
        userMapper.updateByPrimaryKey(user1);
        return Response.success();
    }

    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();

        threadPoolTaskExecutor.submit(() -> {
            Long userId2 = LoginUserContextHolder.getUserId();
            log.info("==> 异步线程中获取 userId: {}", userId2);
        });

        // 退出登录 (指定用户 ID)
        StpUtil.logout(userId);

        return Response.success();
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {

        // 新密码
        String newPassword = updatePasswordReqVO.getNewPassword();
        // 密码加密
        String encodePassword = passwordEncoder.encode(newPassword);

        // 获取当前请求对应的用户 ID
        Long userId = LoginUserContextHolder.getUserId();

        UserDO userDO = UserDO.builder()
                .id(userId)
                .password(encodePassword)
                .updateTime(LocalDateTime.now())
                .build();
        // 更新密码
        userMapper.updateByPrimaryKeySelective(userDO);

        return Response.success();
    }


}
